﻿using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;


public class QSqlQueryBilder : IQQueryBuilder
{

    public string Build(QueryFacade qf)
    {
        StringBuilder sb = new StringBuilder();

        if (qf.QueryType == eQQueryType.Select)
        {
            sb.Append("select ");
            if (qf._top > 0)
            {
                sb.AppendFormat(" top {0} ", qf._top);
            }
            //select columns
            sb.AppendLine();
            if (qf.ColumnList.Count == 0)//if select columns name are not specified
            {
                IList<PropertyInfo> properties;
                properties = qf.Table.Type.GetProperties().ToList();

                for (int i = 0; i < properties.Count; i++)
                {
                    var property = properties[i];
                    IQEvaluable column = new QColumn(qf.Table.Alias + "." + property.Name, property.Name);

                    sb.AppendFormat("{0}", column.EvaluteWithAlias());

                    if (i < properties.Count - 1)
                        sb.Append(", ");
                }
                foreach (QTableJoin tj in qf.JoinList)
                {
                    properties = tj.Table.Type.GetProperties().ToList();
                    sb.Append(", ");
                    for (int i = 0; i < properties.Count; i++)
                    {
                        var property = properties[i];
                        IQEvaluable column = new QColumn(tj.Table.Alias + "." + property.Name, property.Name);

                        sb.AppendFormat("{0}", column.EvaluteWithAlias());

                        if (i < properties.Count - 1)
                            sb.Append(", ");
                    }
                }
            }
            else
            {
                for (int i = 0; i < qf.ColumnList.Count; i++)
                {
                    IQEvaluable column = (IQEvaluable)qf.ColumnList[i];

                    sb.AppendFormat("{0}", column.EvaluteWithAlias());

                    if (i < qf.ColumnList.Count - 1)
                        sb.Append(", ");

                }
            }
        }
        if (qf.QueryType == eQQueryType.Update)
        {
            sb.Append("update " + qf.Table.Alias);
            sb.AppendLine();
            sb.Append("set ");
            for (int i = 0; i < qf.SetList.Count; i++)
            {
                QSet set = qf.SetList[i];
                sb.AppendFormat(set.Evalute());
                if (i < qf.SetList.Count - 1)
                {
                    sb.AppendLine(",");
                }

            }
        }
        if (qf.QueryType == eQQueryType.Delete)
        {
            sb.Append("delete " + qf.Table.Alias);
        }
        if (qf.QueryType == eQQueryType.Insert)
        {
            sb.Append("insert into " + qf.Table.Type.Name);

            StringBuilder sbColumns = new StringBuilder();
            StringBuilder sbValues = new StringBuilder();
            foreach (InsertColumn item in qf.InsertColumnList)
            {
                sbColumns.Append(item.ColumnName);
                sbValues.Append(item.Value.Evalute());
                if (item != qf.InsertColumnList.Last())
                {
                    sbColumns.Append(", ");
                    sbValues.Append(", ");
                }
            }
            sb.AppendFormat("({0})", sbColumns.ToString());
            sb.AppendFormat("values ({0})", sbValues.ToString());
        }
        if (qf.QueryType != eQQueryType.Insert)
        {
            //joins
            sb.AppendLine();
            sb.AppendFormat("from {0} {1}", qf.Table.Name, qf.Table.Alias);
            for (int i = 0; i < qf.JoinList.Count; i++)
            {
                QTableJoin tj = qf.JoinList[i];
                sb.AppendLine();
                // sb.AppendFormat("inner join {0} {1} on {2} = {3}", tj.TableName, tj.Alias, tj.Key, tj.KeyRef);
                if (tj.JoinType == eQJoinType.LeftJoin)
                    sb.Append("left outer");
                else
                    sb.Append("inner");
                sb.AppendFormat(" join {0} {1} on ", tj.Table.Name, tj.Table.Alias);
                for (int j = 0; j < tj.Criterias.Count; j++)
                {
                    IQEvaluable criteria = tj.Criterias[j];
                    sb.AppendFormat(" {0} ", criteria.Evalute());
                    if (j < tj.Criterias.Count - 1)
                        sb.Append(" and ");
                }
            }
            //where clause
            if (qf.ClauseList.Count > 0)
            {
                sb.AppendLine();
                sb.AppendFormat("where ");
                for (int i = 0; i < qf.ClauseList.Count; i++)
                {
                    //IQCriteria clause = qf.Clauses[i];              
                    IQEvaluable clause = qf.ClauseList[i];
                    if (i > 0 && ((QCriteriaBase)clause).LogicalOp == null)
                    {
                        ((QCriteriaBase)clause).LogicalOp = eQLogicOperator.And;
                    }
                    sb.AppendLine();
                    sb.Append(clause.Evalute());
                }
            }
            //group by 
            if (qf.QueryType == eQQueryType.Select && qf.GroupList.Count > 0)
            {
                sb.AppendLine();
                sb.AppendFormat("group by ");
                for (int i = 0; i < qf.GroupList.Count; i++)
                {
                    string group = qf.GroupList[i];
                    sb.Append(group);
                    if (i < qf.GroupList.Count - 1)
                        sb.Append(", ");
                }
            }
            //having clause
            if (qf.QueryType == eQQueryType.Select && qf.HavingClauseList.Count > 0)
            {
                sb.AppendLine();
                sb.AppendFormat("having ");
                for (int i = 0; i < qf.HavingClauseList.Count; i++)
                {
                    IQEvaluable clause = qf.HavingClauseList[i];
                    sb.AppendLine();
                    sb.Append(clause.Evalute());
                }
            }
            //order by 
            if (qf.QueryType == eQQueryType.Select && qf.OrderList.Count > 0)
            {
                sb.AppendLine();
                sb.Append("Order By ");
                for (int i = 0; i < qf.OrderList.Count; i++)
                {
                    QOrder order = qf.OrderList[i];
                    sb.Append(order.Evalute());
                    if (i < qf.OrderList.Count - 1) sb.Append(", ");
                }
            }
        }
        System.Diagnostics.Debug.Print("--------------------------------------------");
        System.Diagnostics.Debug.Print(sb.ToString());
        return sb.ToString();
    }
}
